package BitCreeekClient;
/**
 * @author Ivan Litsvinenka & Emanuele Ricci
 * Classe che implementa il comportamento del Thread del Tracker che gestisce le connessioni TCP relative a un torrent
 *
 */

import BitCreekLib.Host;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketException;


public class PeerP2PServerWorker implements Runnable {
    String torrentName;
    Socket socket;
    Host host;

    public PeerP2PServerWorker ( String torrentName, Socket socket ) {
        this.torrentName = torrentName;
        this.socket = socket;
        this.host = new Host ( this.socket.getInetAddress (), 0 );
    }

    public void run () {
        try {
            if ( !Client.downloads.get ( torrentName ).canAcceptMoreConnections ( socket.getInetAddress () ) ) {
                ObjectOutputStream output = new ObjectOutputStream ( socket.getOutputStream () );
                output.writeObject ( new P2P_Packet ( P2P_MessageType.ERROR, "No more slots" ) );
                socket.close ();
                return;
            }
            while ( true ) {
                ObjectOutputStream output = new ObjectOutputStream ( socket.getOutputStream () );
                ObjectInputStream input = new ObjectInputStream ( socket.getInputStream () );
                
                P2P_Packet req;
                req = ( P2P_Packet ) input.readObject ();
                switch ( req.getType () ) {
                    case GET_PART: {
                        
                        
                        if ( Client.downloads.get ( torrentName ).parts[ ( ( Number ) req.getValue () ).intValue () ].getStatus().equals( PartStatusType.COMPLETE ) ) {
                        	
	                        output.writeObject ( new P2P_Packet ( P2P_MessageType.OK, Client.downloads.get ( torrentName ).getData ( ( ( Number ) req.getValue () ).intValue () ) ) );
	                        // Updating peer values
	                        for ( Host h : Client.downloads.get ( torrentName ).swarmInfo.keySet() ) {
	                            if( h.equals ( host ) ){
	                                Client.downloads.get ( torrentName ).swarmInfo.get ( h ).setDownloaded ( Client.downloads.get ( torrentName ).swarmInfo.get ( h ).getDownloaded () + Client.downloads.get ( torrentName ).getData ( ( ( Number ) req.getValue () ).intValue () ).length );
	                                if ( Client.downloads.get ( torrentName ).swarmInfo.get ( h ).getFirstTimeDownloaded () == -1 ) {
	                                    Client.downloads.get ( torrentName ).swarmInfo.get ( h ).setFirstTimeDownloaded ( System.currentTimeMillis () );
	                                }
	                                break;
	                            }
	                            
	
	                        }
                        } else {
                        	output.writeObject ( new P2P_Packet ( P2P_MessageType.ERR_PART_INCOMPLETE, "Part is not avaible" ) );
                        }
                        break;
                    }
                    case GET_PARTS:
                        // Parts request
                        output.writeObject ( new P2P_Packet ( P2P_MessageType.OK, Client.downloads.get ( torrentName ).parts ) );
                        break;
                    case NEW_PARTS: {
                        // New parts notification;
                        boolean done = false;
                        for ( int i = 0; i < Client.downloads.get ( torrentName ).getConnectedPeers ().size () && !done; i++ ) {
                            if ( Client.downloads.get ( torrentName ).getConnectedPeers ().get ( i ).getAddress ().equals ( socket.getInetAddress () ) ) {
                                PeerInfo tmp = Client.downloads.get ( torrentName ).getSwarm ().get ( Client.downloads.get ( torrentName ).getConnectedPeers ().get ( i ) );
                                tmp.setPeerParts ( ( Part[] ) req.getValue () );
                                
                                Client.downloads.get ( torrentName ).getSwarm ().put ( Client.downloads.get ( torrentName ).getConnectedPeers ().get ( i ), tmp );
                                done = true;
                            }
                        }
                        output.writeObject ( new P2P_Packet ( P2P_MessageType.OK, null ) );
                        break;
                    }
                    case OK:
                        break;
                }
                applicationWindow.c.fireGUIEvent ( new GUIEvent ( Client.downloads.get ( torrentName ) ) );
            }
        } catch ( SocketException e ) {
            // Socket con quel client morto. Elimino dallo swarm.

        } catch ( Exception e ) {
            try {
                socket.close ();
            } catch ( IOException e1 ) {
                e1.printStackTrace ();
            }
            Client.downloads.get ( torrentName ).getConnectedPeers ().remove ( this.host );
            Client.downloads.get ( torrentName ).getSwarm ().remove ( this.host );

            e.printStackTrace ();
            try {
                socket.close ();
            } catch ( Exception e1 ) {
                Log.add ( "Socke Closed" );
            }
        }

    }
}
